

#ifndef COM_CTRL_H
#define COM_CTRL_H

#include <stdint.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#include "controlcan.h"

#define COM_PARAM_MAX 10

#define CAN_ID_STD                  (0x00000000U)  /*!< Standard Id */
#define CAN_ID_EXT                  (0x00000004U)  /*!< Extended Id */

#define CAN_RTR_DATA                (0x00000000U)  /*!< Data frame   */
#define CAN_RTR_REMOTE              (0x00000002U)  /*!< Remote frame */

typedef struct {
    uint32_t Group;    /*!<  Specifies the tool number.*/
    uint32_t Chn;      /*!<  Specifies the can channel number.*/
    uint32_t StdId;    /*!< Specifies the standard identifier.
                            This parameter must be a number between Min_Data = 0 and Max_Data = 0x7FF. */
    uint32_t ExtId;    /*!< Specifies the extended identifier.
                            This parameter must be a number between Min_Data = 0 and Max_Data = 0x1FFFFFFF. */
    uint32_t IDE;      /*!< Specifies the type of identifier for the message that will be transmitted.
                            This parameter can be a value of @ref CAN_identifier_type */
    uint32_t RTR;      /*!< Specifies the type of frame for the message that will be transmitted.
                            This parameter can be a value of @ref CAN_remote_transmission_request */
    uint32_t DLC;      /*!< Specifies the length of the frame that will be transmitted.
                            This parameter must be a number between Min_Data = 0 and Max_Data = 8. */
    uint32_t Timestamp; /*!< Specifies the timestamp counter value captured on start of frame reception.
                            @note: Time Triggered Communication Mode must be enabled.
                            This parameter must be a number between Min_Data = 0 and Max_Data = 0xFFFF. */
    uint32_t FilterMatchIndex; /*!< Specifies the index of matching acceptance filter element.
                            This parameter must be a number between Min_Data = 0 and Max_Data = 0xFF. */
    uint8_t Data[8];
} CAN_Frame_Desc;

typedef enum {
    COM_USBCAN    = 0,     //USB2CAN
    COM_UDPCAN    = 1,     //UDP2CAN
    COM_ECAT      = 2,     //ethercat
    COM_MAX,
    //...
} Com_Type;


class Com_Ctrl {
public:
    Com_Ctrl(Com_Type type, void *param, uint8_t len);
    virtual ~Com_Ctrl() = 0;
    virtual int32_t com_ctrl_init();
    virtual int32_t com_ctrl_deinit();

    inline void *get_com_param() {return param;}
    inline Com_Type get_com_type() {return type;}

    inline uint8_t is_ready() {return this->ready;}
    inline uint8_t com_thread_getflag(){return run_flag;}
    void com_thread_enable(){this->run_flag = 1;}
    void com_thread_disable(){this->run_flag = 0;}

    virtual int32_t send_func(void *pf, uint8_t num = 1) = 0;  
    virtual void *com_receive_loop() = 0;
    friend void *com_receive_thread(void *param);

protected:

private:
    Com_Type type;                
    uint32_t param[COM_PARAM_MAX];

    uint8_t ready = 0;
    uint8_t run_flag = 0;
    pthread_t pid;
};

namespace USBCAN {
    #define USB_TOOL_MAX      (4)
    #define USBCAN_BAUD_1M         (1000000)

    #define USBCAN_INFO_MAX     (50)
    #define USBCAN_RECVFRAME_MAX   (3000)      //接收缓存, 设为3000为佳
    #define USBCAN_SENDFRAME_MAX   (8)

    typedef struct {
        uint32_t baudrate;
    } USBCAN_Ctrl_Param;

    class USBCAN_Ctrl : public Com_Ctrl{
    public:
        USBCAN_Ctrl(void *param, uint8_t len);
        ~USBCAN_Ctrl();
        int32_t com_ctrl_init() override;
        int32_t com_ctrl_deinit() override;

        int32_t send_func(void *pf, uint8_t num = 1);
        void *com_receive_loop();
            
    protected:

    private:
        VCI_BOARD_INFO pInfo[USBCAN_INFO_MAX];      //用来获取设备信息
        VCI_CAN_OBJ recv[USBCAN_RECVFRAME_MAX];        //接收缓存
        VCI_CAN_OBJ send[USBCAN_SENDFRAME_MAX];        //待发送帧   

        uint32_t baudrate;
    };

}

using namespace USBCAN;

#endif